#include "dwarf/internal.hpp"
using namespace std;

namespace dwarf
{
/**
 * @brief 用于根据给定的DW_AT名称和DW_FORM形式来解析属性的类型
 *
 * @param name
 * @param form
 * @return value::type
 */
static value::type resolve_type(DW_AT name, DW_FORM form)
{
    switch (form) {
    case DW_FORM::addr:
        return value::type::address;

    case DW_FORM::block:
    case DW_FORM::block1:
    case DW_FORM::block2:
    case DW_FORM::block4:
        switch (name) {
        case DW_AT::location:
        case DW_AT::byte_size:
        case DW_AT::bit_offset:
        case DW_AT::bit_size:
        case DW_AT::string_length:
        case DW_AT::lower_bound:
        case DW_AT::return_addr:
        case DW_AT::bit_stride:
        case DW_AT::upper_bound:
        case DW_AT::count:
        case DW_AT::data_member_location:
        case DW_AT::frame_base:
        case DW_AT::segment:
        case DW_AT::static_link:
        case DW_AT::use_location:
        case DW_AT::vtable_elem_location:
        case DW_AT::allocated:
        case DW_AT::associated:
        case DW_AT::data_location:
        case DW_AT::byte_stride:
            return value::type::exprloc;
        default:
            return value::type::block;
        }

    case DW_FORM::data4:
    case DW_FORM::data8:
        switch (name) {
        case DW_AT::location:
        case DW_AT::stmt_list:
        case DW_AT::string_length:
        case DW_AT::return_addr:
        case DW_AT::start_scope:
        case DW_AT::data_member_location:
        case DW_AT::frame_base:
        case DW_AT::macro_info:
        case DW_AT::segment:
        case DW_AT::static_link:
        case DW_AT::use_location:
        case DW_AT::vtable_elem_location:
        case DW_AT::ranges:
            goto sec_offset;
        default:
            break;
        }
    case DW_FORM::data1:
    case DW_FORM::data2:
        return value::type::constant;
    case DW_FORM::udata:
        return value::type::uconstant;
    case DW_FORM::sdata:
        return value::type::sconstant;

    case DW_FORM::exprloc:
        return value::type::exprloc;

    case DW_FORM::flag:
    case DW_FORM::flag_present:
        return value::type::flag;

    case DW_FORM::ref1:
    case DW_FORM::ref2:
    case DW_FORM::ref4:
    case DW_FORM::ref8:
    case DW_FORM::ref_addr:
    case DW_FORM::ref_sig8:
    case DW_FORM::ref_udata:
        return value::type::reference;

    case DW_FORM::string:
    case DW_FORM::strp:
        return value::type::string;

    case DW_FORM::indirect:
        return value::type::invalid;

    case DW_FORM::sec_offset:
    sec_offset:
        switch (name) {
        case DW_AT::stmt_list:
            return value::type::line;

        case DW_AT::location:
        case DW_AT::string_length:
        case DW_AT::return_addr:
        case DW_AT::data_member_location:
        case DW_AT::frame_base:
        case DW_AT::segment:
        case DW_AT::static_link:
        case DW_AT::use_location:
        case DW_AT::vtable_elem_location:
            return value::type::loclist;

        case DW_AT::macro_info:
            return value::type::mac;

        case DW_AT::start_scope:
        case DW_AT::ranges:
            return value::type::rangelist;
        case DW_AT::lo_user...DW_AT::hi_user:
            //HACK: ignore vendor extensions
            return value::type::invalid;

        default:
            throw format_error("DW_FORM_sec_offset not expected for attribute " +
                               to_string(name));
        }
    }
    throw format_error("unknown attribute form " + to_string(form));
}

/**
 * @brief 这是一个属性规范的结构体，包含属性的名称、表单和类型。构造函数接受DW_AT名称和DW_FORM形式作为参数，并使用resolve_type函数来解析属性的类型
 * 
 * @param name 
 * @param form 
 */
attribute_spec::attribute_spec(DW_AT name, DW_FORM form)
    : name(name), form(form), type(resolve_type(name, form))
{
}

bool abbrev_entry::read(cursor *cur)
{
    attributes.clear();
    code = cur->uleb128();
    if (!code)
        return false;

    tag = (DW_TAG)cur->uleb128();
    children = cur->fixed<DW_CHILDREN>() == DW_CHILDREN::yes;
    while (1) {
        DW_AT name = (DW_AT)cur->uleb128();
        DW_FORM form = (DW_FORM)cur->uleb128();
        if (name == (DW_AT)0 && form == (DW_FORM)0)
            break;
        attributes.push_back(attribute_spec(name, form));
    }
    attributes.shrink_to_fit();
    return true;
}
} // namespace dwarf
